﻿using EFCore.BulkExtensions;
using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using iWare.Wms.Core;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Linq.Dynamic.Core;
using System.Transactions;
using Yitter.IdGenerator;

namespace iWare.Wms.Application
{
    /// <summary>
    /// 单据出库服务
    /// </summary>
    [Route("api/ManualOrderIssue")]
    [ApiDescriptionSettings("单据出库", Name = "ManualOrderIssue", Order = 100)]

    public class OrderIssueService : IDynamicApiController, ITransient
    {
        private readonly ISqlRepository<ERPDbContextLocator> _erpRep;
        private readonly IRepository<WareDictData, MasterDbContextLocator> _wareDictDataRep; //仓库字典值仓储
        private readonly IRepository<WareArea, MasterDbContextLocator> _wareAreaRep; //所属库区仓储
        private readonly IRepository<WareMaterial, MasterDbContextLocator> _wareMaterialRep; //物料仓储
        private readonly IRepository<WareContainer, MasterDbContextLocator> _wareContainerRep; //容器仓储
        private readonly IRepository<WareLocation, MasterDbContextLocator> _wareLocationRep; //库位仓储
        private readonly IRepository<WareTask, MasterDbContextLocator> _wareTaskRep; //任务仓储
        private readonly IRepository<WareStock, MasterDbContextLocator> _wareStockRep; //库存仓储
        private readonly IRepository<WareSortOrder, MasterDbContextLocator> _wareSortOrderRep; //分拣仓储
        private readonly IRepository<WareOrder, MasterDbContextLocator> _wareOrderRep; //单据仓储
        private readonly IRepository<WareOrderDetails, MasterDbContextLocator> _wareOrderDetailsRep; //单据明细仓储
        private readonly IRepository<WareContainerVsMaterial, MasterDbContextLocator> _wareContainerVsMaterialRep; //容器与物料关系仓储
        private readonly IRepository<WareLocationVsContainer, MasterDbContextLocator> _wareLocationVsContainerRep; //库位与容器关系仓储
        private readonly IRepository<ShipmentDeliveryAppointment, MasterDbContextLocator> _shipmentDeliveryAppointment; //发货预约管理

        #region 默认
        /// <summary>
        /// 默认
        /// </summary>
        /// <param name="erpRep"></param>
        /// <param name="wareAreaRep"></param>
        /// <param name="wareDictDataRep"></param>
        /// <param name="wareMaterialRep"></param>
        /// <param name="wareContainerRep"></param>
        /// <param name="wareLocationRep"></param>
        /// <param name="wareTaskRep"></param>
        /// <param name="wareStockRep"></param>
        /// <param name="wareSortOrderRep"></param>
        /// <param name="wareOrderRep"></param>
        /// <param name="wareOrderDetailsRep"></param>
        /// <param name="wareContainerVsMaterialRep"></param>
        /// <param name="wareLocationVsContainerRep"></param>
        /// <param name="shipmentDeliveryAppointment"></param>
        public OrderIssueService(
               ISqlRepository<ERPDbContextLocator> erpRep,
               IRepository<WareDictData, MasterDbContextLocator> wareDictDataRep,
               IRepository<WareArea, MasterDbContextLocator> wareAreaRep,
               IRepository<WareMaterial, MasterDbContextLocator> wareMaterialRep,
               IRepository<WareContainer, MasterDbContextLocator> wareContainerRep,
               IRepository<WareLocation, MasterDbContextLocator> wareLocationRep,
               IRepository<WareTask, MasterDbContextLocator> wareTaskRep,
               IRepository<WareStock, MasterDbContextLocator> wareStockRep,
               IRepository<WareSortOrder, MasterDbContextLocator> wareSortOrderRep,
               IRepository<WareOrder, MasterDbContextLocator> wareOrderRep,
               IRepository<WareOrderDetails, MasterDbContextLocator> wareOrderDetailsRep,
               IRepository<WareContainerVsMaterial, MasterDbContextLocator> wareContainerVsMaterialRep,
               IRepository<WareLocationVsContainer, MasterDbContextLocator> wareLocationVsContainerRep,
                IRepository<ShipmentDeliveryAppointment, MasterDbContextLocator> shipmentDeliveryAppointment
        )
        {
            _erpRep = erpRep;
            _wareDictDataRep = wareDictDataRep;
            _wareAreaRep = wareAreaRep;
            _wareMaterialRep = wareMaterialRep;
            _wareContainerRep = wareContainerRep;
            _wareLocationRep = wareLocationRep;
            _wareTaskRep = wareTaskRep;
            _wareStockRep = wareStockRep;
            _wareSortOrderRep = wareSortOrderRep;
            _wareOrderRep = wareOrderRep;
            _wareOrderDetailsRep = wareOrderDetailsRep;
            _wareContainerVsMaterialRep = wareContainerVsMaterialRep;
            _wareLocationVsContainerRep = wareLocationVsContainerRep;
            _shipmentDeliveryAppointment = shipmentDeliveryAppointment;
        }
        #endregion

        /// <summary>
        /// 分页查询单据出库信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("Page")]
        public async Task<PageResult<OrderIssueOutput>> Page([FromQuery] OrderIssueSearch input)
        {
            // 查询单据类型对应的ID
            var orderCategory = (await _wareDictDataRep.FirstOrDefaultAsync(z => z.Value == input.OrderCategory)).Code;

            var list = await _wareOrderRep.DetachedEntities
                   .Where(input.OrderStatus != IssueStausEnum.ALL, u => u.OrderStatus == input.OrderStatus)
                   //.Where(input.OrderType != IssueTypeEnum.ALL, u => u.OrderType == input.OrderType)
                   .Where(!string.IsNullOrEmpty(input.OrderNo), u => EF.Functions.Like(u.OrderNo, $"%{input.OrderNo.Trim()}%"))
                   .Where(!string.IsNullOrEmpty(input.ProjectCode), u => EF.Functions.Like(u.ProjectCode, $"%{input.ProjectCode.Trim()}%"))
                   .Where(!string.IsNullOrEmpty(input.OrderCategory) && orderCategory != "2D01", u => u.OrderCategory == orderCategory)
                   .Where(orderCategory == "2D01", u => u.OrderCategory == "2D01" || u.OrderCategory == "1108" || u.OrderCategory == "2301")
                   .Where(!string.IsNullOrEmpty(input.SearchBeginTime), u => u.CreatedTime >= DateTime.Parse(input.SearchBeginTime.Trim()) &&
                    u.CreatedTime <= DateTime.Parse(input.SearchEndTime.Trim()))
                   .OrderBy(t => t.OrderStatus)
                   .ThenByDescending(u => u.CreatedTime)
                   .ThenByDescending(u => u.UpdatedTime)
                   .ProjectToType<OrderIssueOutput>()
                   .ToADPagedListAsync(input.PageNo, input.PageSize);

            foreach (var item in list.Rows)
            {
                var orderDetails = await _wareOrderDetailsRep.DetachedEntities.Where(u => u.OrderId == item.Id).ToListAsync();
                item.ActualQuantityTotal = orderDetails != null ? orderDetails.Sum(t => t.ActualQuantity) : new decimal(0.00);

                if (!string.IsNullOrEmpty(item.OrderCategory))
                {
                    var wareDictData = await _wareDictDataRep.FirstOrDefaultAsync(z => z.Code == item.OrderCategory);
                    item.OrderCategory = wareDictData != null ? wareDictData.Value : "N/A";
                }
                //if (item.UpdatedTime.ToString() == "0001/1/1 0:00:00 +00:00") item.UpdatedTime = null;
            }

            return list;
        }

        /// <summary>
        /// 分页查询单据出库明细信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("DetailPage")]
        public async Task<PageResult<WareOrderDetailsOutput>> DetailPage([FromQuery] OrderIssueDetailSearch input)
        {
            var list = await _wareOrderDetailsRep.DetachedEntities.Where(u => u.OrderId == input.Id)
                   .Where(!string.IsNullOrEmpty(input.ProjectCode), u => u.ProjectCode == input.ProjectCode)
                   .Where(!string.IsNullOrEmpty(input.Code), u => u.Code == input.Code)
                   .OrderBy(u => u.XuHao)
                   .ProjectToType<WareOrderDetailsOutput>()
                   .ToADPagedListAsync(input.PageNo, input.PageSize);

            foreach (var item in list.Rows)
            {
                //查询库存
                var stockModel = await _wareStockRep.FirstOrDefaultAsync(z => z.ContainerCode == item.ContainerCode
                && z.ProjectCode == item.ProjectCode && z.Code == item.Code && item.SpecificationModel == item.SpecificationModel);
                item.CurrentQuantity = stockModel == null ? new decimal(0.00) : stockModel.CurrentQuantity;

                //查询库位状态
                if (item.LocationCode == "N/A") item.LocationStatus = LocationStatusEnum.kongxian;
                else
                {
                    if (!string.IsNullOrEmpty(item.LocationCode))
                    {
                        var wareLocation = await _wareLocationRep.FirstOrDefaultAsync(z => z.Code == item.LocationCode);
                        item.LocationStatus = wareLocation != null ? wareLocation.LocationStatus : LocationStatusEnum.kongxian;

                        var wareArea = await _wareAreaRep.FirstOrDefaultAsync(z => z.Id == wareLocation.AreaID);
                        item.ReservoirArea = wareArea != null ? wareArea.AreaName : "";
                    }
                }
            }

            return list;
        }

        /// <summary>
        /// 分页查询创建单据出库对应的库存信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet("StockPage")]
        public async Task<PageResult<OrderIssueStockOutput>> StockPage([FromQuery] OrderIssueStockInput input)
        {
            //获取该库区下的所以库位信息
            var locationList = await _wareLocationRep.Where(input.AreaID != -10, p => p.AreaID == input.AreaID).Select(n => n.Code).ToListAsync();
            var list = await _wareStockRep.DetachedEntities
                   .Where(u => u.CurrentQuantity > new decimal(0.00))
                   .Where(!string.IsNullOrEmpty(input.ContainerCode), u => EF.Functions.Like(u.ContainerCode, $"%{input.ContainerCode.Trim()}%"))
                   .Where(!string.IsNullOrEmpty(input.LocationCode), u => EF.Functions.Like(u.LocationCode, $"%{input.LocationCode.Trim()}%"))
                   .Where(u => locationList.Contains(u.LocationCode))
                   .Where(!string.IsNullOrEmpty(input.ProjectCode), u => EF.Functions.Like(u.ProjectCode, $"%{input.ProjectCode.Trim()}%"))
                   .Where(!string.IsNullOrEmpty(input.Code), u => EF.Functions.Like(u.Code, $"%{input.Code.Trim()}%"))
                   .Where(z => z.StockQuantity > new decimal(0.00))
                   .OrderByDescending(t => t.UpdatedTime)
                   .ProjectToType<OrderIssueStockOutput>()
                   .ToADPagedListAsync(input.PageNo, input.PageSize);

            foreach (var item in list.Rows)
            {
                if (item.LocationCode != "N/A") item.OriginalLocationCode = (await _wareLocationRep.FirstOrDefaultAsync(z => z.Code == item.LocationCode)).OriginalLocationCode;

                //查询库位状态
                if (item.LocationCode == "N/A") item.LocationStatus = LocationStatusEnum.kongxian;
                else
                {
                    var wareLocation = await _wareLocationRep.FirstOrDefaultAsync(z => z.Code == item.LocationCode);
                    item.LocationStatus = wareLocation.LocationStatus;
                }
            }

            return list;
        }

        /// <summary>
        /// 新增单据出库
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("Add")]
        public async Task Add([FromBody] AddOrderIssueInput input)
        {
            if (input.WareOrderDetailss.Count == 0) throw Oops.Oh("出库物料不能为空");

            //系统生成出库单据号
            var orderNo = YitIdHelper.NextId().ToString();

            //构建出库单据主表信息
            var wareOrder = new WareOrder()
            {
                OrderNo = orderNo,
                OrderCategory = input.OrderCategory, //单别（1204_异库调拨单、1203_装配调拨单、1201_库位调拨单、2D01_零组件发货）
                OrderType = IssueTypeEnum.SHOUDONG,
                OrderStatus = IssueStausEnum.NOTZHIXING,
                ProjectCode = input.WareOrderDetailss.Select(t => t.ProjectCode).FirstOrDefault(),
                OrderQuantityTotal = input.WareOrderDetailss.Sum(t => t.OrderQuantity)
            };
            await _wareOrderRep.InsertAsync(wareOrder);

            //构建单据明细信息
            foreach (var item in input.WareOrderDetailss)
            {
                var orderDetails = item.Adapt<WareOrderDetails>();
                orderDetails.OrderId = wareOrder.Id;
                // 新增单据明细信息
                await _wareOrderDetailsRep.InsertAsync(orderDetails);
            }
        }

        /// <summary>
        /// 编辑单据出库
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("Edit")]
        public async Task Edit([FromBody] EditOrderIssueInput input)
        {
            if (input.WareOrderDetailss.Count == 0) throw Oops.Oh("出库物料不能为空");

            var wareOrder = await _wareOrderRep.DetachedEntities.Where(z => z.Id == input.Id).ProjectToType<WareOrder>().FirstOrDefaultAsync();
            if (wareOrder == null) throw Oops.Oh("数据不存在");

            //删除原来单据明细记录
            foreach (var itemDetail in wareOrder.WareOrderDetails)
            {
                await _wareOrderDetailsRep.DeleteAsync(itemDetail);
            }

            // 更新单据主表项目编号和单据数
            wareOrder.ProjectCode = input.WareOrderDetailss.Select(t => t.ProjectCode).FirstOrDefault();
            wareOrder.OrderQuantityTotal = input.WareOrderDetailss.Sum(t => t.OrderQuantity);
            await _wareOrderRep.UpdateAsync(wareOrder);

            //构建单据明细信息
            foreach (var item in input.WareOrderDetailss)
            {
                var orderDetails = item.Adapt<WareOrderDetails>();
                orderDetails.OrderId = wareOrder.Id;

                // 新增单据明细信息
                await _wareOrderDetailsRep.InsertAsync(orderDetails);
            }
        }

        /// <summary>
        /// 删除单据主表信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("Delete")]
        public async Task Delete([FromBody] DeleteOrderIssueInput input)
        {
            var order = await _wareOrderRep.DetachedEntities.Where(z => z.Id == input.Id).ProjectToType<WareOrder>().FirstOrDefaultAsync();
            if (order == null) throw Oops.Oh("数据不存在");

            await _wareOrderRep.DeleteAsync(order);
        }

        /// <summary>
        /// 删除单个单据明细信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("DetailsDelete")]
        public async Task DetailsDelete([FromBody] DeleteOrderDetailsIssueInput input)
        {
            var orderDetails = await _wareOrderDetailsRep.FirstOrDefaultAsync(z => z.Id == input.Id);
            if (orderDetails == null) throw Oops.Oh("数据不存在");

            await _wareOrderDetailsRep.DeleteAsync(orderDetails);
        }

        /// <summary>
        /// 单据下发
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("BatchTransferIssue")]
        //[UnitOfWork]
        public async Task BatchTransferIssue([FromBody] BatchTransferIssueInput input)
        {
            // 查询单据
            var wareOrder = await _wareOrderRep.FirstOrDefaultAsync(z => z.Id == input.Id);
            if (wareOrder == null) throw Oops.Oh("数据不存在");

            // 查询单据明细
            var wareOrderDetails = await _wareOrderDetailsRep.DetachedEntities.Where(z => z.OrderId == input.Id).ToListAsync();
            foreach (var orderDetails in wareOrderDetails)
            {
                if (string.IsNullOrEmpty(orderDetails.LocationCode)) throw Oops.Oh("请操作推荐库位");
            }

            using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }, TransactionScopeAsyncFlowOption.Enabled))
            {
                try
                {
                    // 统计实际下发数
                    var actualQuantitySum = new decimal(0.00);

                    foreach (var orderDetails in wareOrderDetails)
                    {
                        // 单据数等于实际出库数就不要下发了
                        if (orderDetails.ActualQuantity == orderDetails.OrderQuantity) continue;

                        //查询库存
                        var stockModel = await _wareStockRep.FirstOrDefaultAsync(z => z.ContainerCode == orderDetails.ContainerCode
                        && z.ProjectCode == orderDetails.ProjectCode && z.Code == orderDetails.Code && z.SpecificationModel == orderDetails.SpecificationModel);
                        if (stockModel.CurrentQuantity == new decimal(0.00)) continue;

                        if (orderDetails.LocationCode.Contains("L"))
                        {
                            string litikuLocationCode = orderDetails.LocationCode.Split('L')[1]; //库位编号截取
                            //await LitikuAutoOut(orderDetails.Id, input.ToPlaceId, litikuLocationCode, orderDetails.ContainerCode);
                        }
                        else
                        {
                            await ManualOut(orderDetails.Id); //平库后面也会有自动模式
                        }

                        actualQuantitySum += orderDetails.OrderQuantity - orderDetails.ActualQuantity;
                    }

                    // 更新单据主表状态
                    if (actualQuantitySum == wareOrder.OrderQuantityTotal) wareOrder.OrderStatus = IssueStausEnum.WANCHENG;
                    else wareOrder.OrderStatus = IssueStausEnum.ZHIXINGZHONG;
                    await _wareOrderRep.UpdateAsync(wareOrder);

                    // 提交事务
                    scope.Complete();
                }
                catch (Exception ex)
                {
                    throw Oops.Oh("[BatchTransferIssue]批量物料出库下发异常：" + ex.StackTrace + "," + ex.Message);
                }
                finally
                {
                    scope.Dispose();
                }
            }
        }

        /// <summary>
        /// 2023-2-28单个物料出库下发【最新规则：没有操作推荐库存系统默认先查询平库库存，平库库存不满足再出立体库】
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("NewSingleTransferIssue")]
        public async Task NewSingleTransferIssue([FromBody] SingleTransferIssueInput input)
        {
            var orderDetails = await _wareOrderDetailsRep.FirstOrDefaultAsync(z => z.Id == input.Id);
            if (orderDetails == null) throw Oops.Oh("数据不存在");

            // 单据数等于实际出库数就不要下发了
            if (orderDetails.OrderQuantity == orderDetails.ActualQuantity) throw Oops.Oh("已下发完成");

            try
            {
                string locationCode = string.Empty; //库位编号
                string containerCode = string.Empty; //容器编号

                // 1.查询所有库存
                var stockList = await _wareStockRep.DetachedEntities.Where(z => z.ProjectCode == orderDetails.ProjectCode && z.Code == orderDetails.Code
                && z.SpecificationModel == orderDetails.SpecificationModel).ToListAsync();


                // 没有操作推荐库位
                if (string.IsNullOrEmpty(orderDetails.LocationCode) || orderDetails.LocationCode == "N/A")
                {
                    //查询平库库存
                    var pingkuStockModel = stockList.FirstOrDefault(z => z.LocationCode.Contains('P') && z.ProjectCode == orderDetails.ProjectCode
                    && z.Code == orderDetails.Code && z.SpecificationModel == orderDetails.SpecificationModel
                    && z.CurrentQuantity >= (orderDetails.OrderQuantity - orderDetails.ActualQuantity));
                    if (pingkuStockModel != null)
                    {
                        locationCode = pingkuStockModel.LocationCode;
                        containerCode = pingkuStockModel.ContainerCode;
                    }
                    //平库库存不足查立体库库存
                    var litikuStockModel = stockList.FirstOrDefault(z => z.LocationCode.Contains('L') && z.ProjectCode == orderDetails.ProjectCode
                        && z.Code == orderDetails.Code && z.SpecificationModel == orderDetails.SpecificationModel
                        && z.CurrentQuantity >= (orderDetails.OrderQuantity - orderDetails.ActualQuantity));
                    if (litikuStockModel != null)
                    {
                        locationCode = litikuStockModel.LocationCode;
                        containerCode = litikuStockModel.ContainerCode;
                    }
                }
                else
                {
                    locationCode = orderDetails.LocationCode;
                    containerCode = orderDetails.ContainerCode;
                }
                //在判断是否存在相同的分拣托盘
                foreach (var stock in stockList)
                {
                    // 2.根据容器查询有没有分拣信息
                    var wareSortOrder = await _wareSortOrderRep.FirstOrDefaultAsync(z => z.ContainerCode == stock.ContainerCode && z.SortStatus != SortStatusEnum.Completed);
                    if (wareSortOrder != null) //判断有没有分拣信息
                    {
                        containerCode = wareSortOrder.ContainerCode;
                        locationCode = stock.LocationCode;
                    }

                }

                #region 判断进入立体库方法还是平库方法
                if (locationCode.Contains("L"))
                {
                    var litikuLocationCode = orderDetails.LocationCode.Split('L')[1]; //库位编号截取
                    await LitikuAutoOut(orderDetails.Id, input.ToPlaceId, litikuLocationCode, orderDetails.ContainerCode);
                }
                else
                {
                    await ManualOut(orderDetails.Id); //平库后面也会有自动模式
                }
                #endregion

                #region 更新单据相关信息
                // 查询单据主表
                var order = await _wareOrderRep.FirstOrDefaultAsync(z => z.Id == orderDetails.OrderId);

                // 单据明细已下发总数
                var actualQuantitySum = (await _wareOrderDetailsRep.DetachedEntities.Where(z => z.OrderId == orderDetails.OrderId)
                    .ToListAsync()).Sum(t => t.ActualQuantity);

                // 更新单据主表状态
                if (actualQuantitySum == order.OrderQuantityTotal) order.OrderStatus = IssueStausEnum.WANCHENG;
                else order.OrderStatus = IssueStausEnum.ZHIXINGZHONG;
                await _wareOrderRep.UpdateAsync(order);

                // 更新单据明细出库的库位和容器
                orderDetails.ContainerCode = containerCode;
                orderDetails.LocationCode = locationCode;
                await _wareOrderDetailsRep.UpdateAsync(orderDetails);
                #endregion

            }
            catch (Exception ex)
            {
                throw Oops.Oh("[SingleTransferIssue]单个物料出库下发异常：" + ex.StackTrace + "," + ex.Message);
            }
            finally
            {

            }

        }

        /// <summary>
        /// 2023-2-28批量物料出库下发【最新规则：没有操作推荐库存系统默认先查询平库库存，平库库存不满足再出立体库】
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("NewBatchTransferIssue")]
        public async Task NewBatchTransferIssue([FromBody] BatchTransferIssueInput input)
        {
            // 查询单据
            var wareOrder = await _wareOrderRep.FirstOrDefaultAsync(z => z.Id == input.Id);
            if (wareOrder == null) throw Oops.Oh("数据不存在");

            try
            {
                // 查询单据明细
                var wareOrderDetails = await _wareOrderDetailsRep.DetachedEntities.Where(z => z.OrderId == input.Id).ToListAsync();

                // 统计实际下发数
                var actualQuantitySum = new decimal(0.00);

                foreach (var orderDetails in wareOrderDetails)
                {
                    // 单据数等于实际出库数就不要下发了
                    if (orderDetails.ActualQuantity == orderDetails.OrderQuantity) continue;

                    string locationCode = string.Empty;// 库位编号
                    string containerCode = string.Empty; //容器编号

                    // 操作了推荐库位
                    if (string.IsNullOrEmpty(orderDetails.LocationCode) || orderDetails.LocationCode == "N/A")
                    {
                        locationCode = orderDetails.LocationCode;
                        containerCode = orderDetails.ContainerCode;
                    }

                    // 1.查询所有库存
                    var stockList = await _wareStockRep.DetachedEntities.Where(z => z.ProjectCode == orderDetails.ProjectCode && z.Code == orderDetails.Code
                    && z.SpecificationModel == orderDetails.SpecificationModel).ToListAsync();

                    foreach (var stock in stockList)
                    {
                        // 2.根据容器查询有没有分拣信息
                        var wareSortOrder = await _wareSortOrderRep.FirstOrDefaultAsync(z => z.ContainerCode == stock.ContainerCode && z.SortStatus != SortStatusEnum.Completed);
                        if (wareSortOrder == null) //3.判断有没有分拣信息
                        {
                            //查询平库库存
                            var pingkuStockModel = stockList.FirstOrDefault(z => z.LocationCode.Contains('P') && z.ProjectCode == orderDetails.ProjectCode
                            && z.Code == orderDetails.Code && z.SpecificationModel == orderDetails.SpecificationModel
                            && z.CurrentQuantity > (orderDetails.OrderQuantity - orderDetails.ActualQuantity));
                            if (pingkuStockModel != null)
                            {
                                locationCode = pingkuStockModel.LocationCode;
                                containerCode = pingkuStockModel.ContainerCode;
                            }
                            //平库库存不足查立体库库存
                            var litikuStockModel = stockList.FirstOrDefault(z => z.LocationCode.Contains('L') && z.ProjectCode == orderDetails.ProjectCode
                                && z.Code == orderDetails.Code && z.SpecificationModel == orderDetails.SpecificationModel
                                && z.CurrentQuantity > (orderDetails.OrderQuantity - orderDetails.ActualQuantity));
                            if (litikuStockModel != null)
                            {
                                locationCode = litikuStockModel.LocationCode;
                                containerCode = litikuStockModel.ContainerCode;
                            }
                        }
                        containerCode = wareSortOrder.ContainerCode;
                        locationCode = stock.LocationCode;
                    }

                    #region 判断进入立体库方法还是平库方法
                    if (locationCode.Contains("L"))
                    {
                        var litikuLocationCode = orderDetails.LocationCode.Split('L')[1]; //库位编号截取
                        await LitikuAutoOut(orderDetails.Id, input.ToPlaceId, litikuLocationCode, orderDetails.ContainerCode);
                    }
                    else
                    {
                        await ManualOut(orderDetails.Id); //平库后面也会有自动模式
                    }

                    actualQuantitySum += orderDetails.OrderQuantity - orderDetails.ActualQuantity;
                    // 更新单据明细对应的库位和容器
                    orderDetails.LocationCode = locationCode;
                    orderDetails.ContainerCode = containerCode;
                    await _wareOrderDetailsRep.UpdateAsync(orderDetails);
                    #endregion
                }

                // 更新单据主表状态
                if (actualQuantitySum == wareOrder.OrderQuantityTotal) wareOrder.OrderStatus = IssueStausEnum.WANCHENG;
                else wareOrder.OrderStatus = IssueStausEnum.ZHIXINGZHONG;
                await _wareOrderRep.UpdateAsync(wareOrder);

                // 提交事务
                //scope.Complete();
            }
            catch (Exception ex)
            {
                throw Oops.Oh("[BatchTransferIssue]批量物料出库下发异常：" + ex.StackTrace + "," + ex.Message);
            }
            finally
            {
                //scope.Dispose();
            }

        }

        #region 删除
        /// <summary>
        /// 楼下立体库下发
        /// </summary>
        /// <param name="Id"></param>
        /// <param name="toPlaceId">出库口</param>
        /// <param name="locationCode">库位编号</param>
        /// <param name="containerCode">容器编号</param>
        /// <returns></returns>
        [NonAction]
        public async Task LitikuAutoOut(long Id, int toPlaceId, string locationCode, string containerCode)
        {
            // 根据ID查询单据明细
            var orderDetails = await _wareOrderDetailsRep.FirstOrDefaultAsync(z => z.Id == Id);

            // 查询单据主表信息
            var order = await _wareOrderRep.FirstOrDefaultAsync(z => z.Id == orderDetails.OrderId);

            //判断任务
            var taskModel = await _wareTaskRep.FirstOrDefaultAsync(p => p.ContainerCode == orderDetails.ContainerCode
            && p.FromLocationCode == orderDetails.LocationCode && p.TaskStatus != TaskStatusEnum.Complete);

            //分拣信息
            var wareSortOrderModel = await _wareSortOrderRep.FirstOrDefaultAsync(p => p.ContainerCode == orderDetails.ContainerCode && p.ProjectCode == orderDetails.ProjectCode
            && p.Code == orderDetails.Code && p.SortStatus == SortStatusEnum.NotProgram);

            var locationModel = new WareLocation(); //定义库位
            var wareLocationVsContainer = new WareLocationVsContainer(); //定义库位与容器关系
            if (taskModel == null && wareSortOrderModel == null)
            {
                //检查托盘
                var wareContainer = await _wareContainerRep.FirstOrDefaultAsync(n => n.Code == orderDetails.ContainerCode && n.ContainerStatus == ContainerStatusEnum.kuwei);
                if (wareContainer == null) throw Oops.Oh("托盘不存在！");

                //检查库位
                locationModel = await _wareLocationRep.FirstOrDefaultAsync(p => p.Code == orderDetails.LocationCode && p.LocationStatus == LocationStatusEnum.cunhuo);
                if (locationModel == null) throw Oops.Oh("库位不存在！");

                //检查库位与容器关系
                wareLocationVsContainer = await _wareLocationVsContainerRep.FirstOrDefaultAsync(
                    n => n.ContainerCode == orderDetails.ContainerCode && n.LocationCode == orderDetails.LocationCode && n.LocationVsContainerStatus == CommonStatus.ENABLE);
                if (wareLocationVsContainer == null) throw Oops.Oh("托盘库位关系不存在！");
            }
        }
        #endregion

        /// <summary>
        /// 伟本LES立体库下发
        /// </summary>
        /// <param name="taskModel">任务表</param>
        /// <param name="wareSortOrderModel">分拣表</param>
        /// <param name="order">出库单据主表</param>
        /// <param name="orderDetails">出库单据明细表</param>
        /// <param name="locationModel">库位表</param>
        /// <param name="wareLocationVsContainer">库位与容器关系表</param>
        /// <returns></returns>
        [NonAction]
        public async Task LitikuSendTask(WareTask taskModel, WareSortOrder wareSortOrderModel, WareOrder order, WareOrderDetails orderDetails, WareLocation locationModel, WareLocationVsContainer wareLocationVsContainer)
        {
            if (taskModel == null && wareSortOrderModel == null)
            {
                //检查容器与物料关系
                var cvmModel = await _wareContainerVsMaterialRep.DetachedEntities.Where(p => p.ContainerCode == orderDetails.ContainerCode
                && p.ContainerVsMaterialStatus == CommonStatus.ENABLE).ToListAsync();

                var OrderNo = "N/A";
                if (cvmModel.Count > 0) OrderNo = YitIdHelper.NextId().ToString();

                foreach (var item in cvmModel)
                {
                    // 入库时组盘信息逻辑删除
                    item.ContainerVsMaterialStatus = CommonStatus.DISABLE;
                    await _wareContainerVsMaterialRep.UpdateAsync(cvmModel);

                    //新增出库绑定记录 禁用
                    var disableList = new WareContainerVsMaterial()
                    {
                        OrderNo = OrderNo,
                        ContainerId = item.ContainerId,
                        MaterialId = item.MaterialId,
                        ContainerCode = item.ContainerCode,
                        ProjectCode = item.ProjectCode,
                        XuHao = item.XuHao,
                        Code = item.Code,
                        Name = item.Name,
                        SpecificationModel = item.SpecificationModel,
                        Unit = item.Unit,
                        InspectionMethod = item.InspectionMethod,
                        BrandName = item.BrandName,
                        BindQuantity = item.BindQuantity,
                        SupplerCode = item.SupplerCode,
                        IsJiaJi = item.IsJiaJi,
                        ContainerVsMaterialStatus = CommonStatus.ENABLE
                    };
                    await _wareContainerVsMaterialRep.InsertNowAsync(disableList);
                }

                //新增任务
                taskModel = new WareTask()
                {
                    OrderNo = OrderNo,
                    TaskModel = TaskModel.ZIDONG,
                    TaskType = TaskType.Out,
                    TaskNo = YitIdHelper.NextId().ToString(),
                    TaskName = order.OrderType == IssueTypeEnum.DIAOBO ? TaskNameConst.DiaoBoDan_AutomaticOut : TaskNameConst.ShouDongDan_AutomaticOut,
                    TaskStatus = TaskStatusEnum.NotProgress,
                    Priority = 1,
                    ContainerCode = orderDetails.ContainerCode,
                    FromLocationCode = orderDetails.LocationCode,
                    ToLocationCode = "N/A"
                };
                await _wareTaskRep.InsertAsync(taskModel);

                //更新库位
                locationModel.LocationStatus = LocationStatusEnum.daichu;
                await _wareLocationRep.UpdateAsync(locationModel);

                //更新关系表
                wareLocationVsContainer.LocationVsContainerStatus = CommonStatus.DISABLE;
                await _wareLocationVsContainerRep.UpdateAsync(wareLocationVsContainer);
            }

            //查询库存
            var stockModel = await _wareStockRep.FirstOrDefaultAsync(z => z.ContainerCode == orderDetails.ContainerCode
            && z.ProjectCode == orderDetails.ProjectCode && z.Code == orderDetails.Code && z.SpecificationModel == orderDetails.SpecificationModel);

            if (stockModel.CurrentQuantity >= orderDetails.OrderQuantity)
            {
                stockModel.CurrentQuantity -= orderDetails.OrderQuantity;
                orderDetails.ActualQuantity = orderDetails.OrderQuantity - orderDetails.ActualQuantity;
            }
            else
            {
                orderDetails.ActualQuantity = stockModel.CurrentQuantity;
                stockModel.CurrentQuantity = 0;
            }
            await _wareStockRep.UpdateAsync(stockModel);
            await _wareOrderDetailsRep.UpdateAsync(orderDetails);

            var OldOrderNo = "N/A";
            if (taskModel != null) OldOrderNo = taskModel.OrderNo;
            if (wareSortOrderModel != null) OldOrderNo = wareSortOrderModel.ContainerOrderNo;

            //空托不执行以下逻辑
            if (OldOrderNo == "N/A") return;

            var ContainerOrderNo = (await _wareContainerVsMaterialRep.FirstOrDefaultAsync(p => p.ContainerCode == orderDetails.ContainerCode
               && p.ContainerVsMaterialStatus == CommonStatus.ENABLE)).OrderNo;

            var wareSortOrder = await _wareSortOrderRep.FirstOrDefaultAsync(z => z.OrderNo == order.OrderNo && z.ContainerOrderNo == ContainerOrderNo && z.ContainerCode == orderDetails.ContainerCode
            && z.ProjectCode == orderDetails.ProjectCode && z.Code == orderDetails.Code && z.SpecificationModel == orderDetails.SpecificationModel && z.SortStatus != SortStatusEnum.Completed);
            if (wareSortOrder == null)
            {
                //新增分拣
                wareSortOrder = new WareSortOrder()
                {
                    OrderNo = order.OrderNo,
                    OrderDetailID = orderDetails.Id,
                    ContainerCode = orderDetails.ContainerCode,
                    ContainerOrderNo = OldOrderNo,
                    ProjectCode = orderDetails.ProjectCode,
                    Code = orderDetails.Code,
                    Name = orderDetails.Name,
                    SpecificationModel = orderDetails.SpecificationModel,
                    Unit = orderDetails.Unit,
                    InspectionMethod = orderDetails.InspectionMethod,
                    SortQuantity = orderDetails.ActualQuantity,
                    ActualQuantity = new decimal(0.00)
                };
                await _wareSortOrderRep.InsertAsync(wareSortOrder);
            }
            else //存在分拣数量累加
            {
                wareSortOrder.SortQuantity += orderDetails.OrderQuantity - orderDetails.ActualQuantity;
                await _wareSortOrderRep.UpdateAsync(wareSortOrder);
            }
        }

        /// <summary>
        /// 平库下发
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        [NonAction]
        public async Task ManualOut(long Id)
        {
            // 查询单据明细
            var orderDetails = await _wareOrderDetailsRep.FirstOrDefaultAsync(z => z.Id == Id);

            //查询库存
            var stockModel = await _wareStockRep.FirstOrDefaultAsync(z => z.ContainerCode == orderDetails.ContainerCode
            && z.ProjectCode == orderDetails.ProjectCode && z.Code == orderDetails.Code && z.SpecificationModel == orderDetails.SpecificationModel);

            // 查询单据主表信息
            var order = await _wareOrderRep.FirstOrDefaultAsync(z => z.Id == orderDetails.OrderId);

            //判断任务
            var taskModel = await _wareTaskRep.FirstOrDefaultAsync(p => p.ContainerCode == orderDetails.ContainerCode && p.TaskStatus != TaskStatusEnum.Complete);

            //分拣信息
            //var wareSortOrderModel = await _wareSortOrderRep.FirstOrDefaultAsync(p => p.ContainerCode == orderDetails.ContainerCode && p.ProjectCode == orderDetails.ProjectCode
            //&& p.Code == orderDetails.Code && p.SortStatus == SortStatusEnum.NotProgram);
            var wareSortOrderModel = await _wareSortOrderRep.FirstOrDefaultAsync(p => p.ContainerCode == orderDetails.ContainerCode && p.SortStatus != SortStatusEnum.Completed);

            if (taskModel == null && wareSortOrderModel == null)
            {
                //if (stockModel.LocationCode == "N/A") throw Oops.Oh("托盘不在库位中！");

                //检查托盘
                var wareContainer = await _wareContainerRep.FirstOrDefaultAsync(n => n.Code == orderDetails.ContainerCode && n.ContainerStatus == ContainerStatusEnum.kuwei);
                if (wareContainer == null) throw Oops.Oh("托盘不存在！");

                //检查库位
                var locationModel = await _wareLocationRep.FirstOrDefaultAsync(p => p.Code == orderDetails.LocationCode && p.LocationStatus == LocationStatusEnum.cunhuo);
                if (wareContainer == null) throw Oops.Oh("库位不存在！");

                //检查库位与容器关系
                var wareLocationVsContainer = await _wareLocationVsContainerRep.FirstOrDefaultAsync(
                    n => n.ContainerCode == orderDetails.ContainerCode && n.LocationCode == orderDetails.LocationCode && n.LocationVsContainerStatus == CommonStatus.ENABLE);
                if (wareLocationVsContainer == null) throw Oops.Oh("托盘库位关系不存在！");

                //检查容器与物料关系
                var cvmModel = await _wareContainerVsMaterialRep.DetachedEntities.Where(p => p.ContainerCode == orderDetails.ContainerCode
                && p.ContainerVsMaterialStatus == CommonStatus.ENABLE).ToListAsync();

                var OrderNo = "N/A";
                if (cvmModel.Count() > 0) OrderNo = YitIdHelper.NextId().ToString();

                foreach (var item in cvmModel)
                {
                    // 入库时组盘信息逻辑删除
                    item.ContainerVsMaterialStatus = CommonStatus.DELETED;
                    await _wareContainerVsMaterialRep.UpdateAsync(cvmModel);

                    //新增出库绑定记录 禁用
                    var disableList = new WareContainerVsMaterial()
                    {
                        OrderNo = OrderNo,
                        ContainerId = item.ContainerId,
                        MaterialId = item.MaterialId,
                        ContainerCode = item.ContainerCode,
                        ProjectCode = item.ProjectCode,
                        XuHao = item.XuHao,
                        Code = item.Code,
                        Name = item.Name,
                        SpecificationModel = item.SpecificationModel,
                        Unit = item.Unit,
                        InspectionMethod = item.InspectionMethod,
                        BrandName = item.BrandName,
                        BindQuantity = item.BindQuantity,
                        SupplerCode = item.SupplerCode,
                        IsJiaJi = item.IsJiaJi,
                        ContainerVsMaterialStatus = CommonStatus.DISABLE
                    };
                    await _wareContainerVsMaterialRep.InsertNowAsync(disableList);

                    //新增出库完成绑定记录 正常
                    var enableList = new WareContainerVsMaterial()
                    {
                        OrderNo = YitIdHelper.NextId().ToString(),
                        ContainerId = item.ContainerId,
                        MaterialId = item.MaterialId,
                        ContainerCode = item.ContainerCode,
                        ProjectCode = item.ProjectCode,
                        XuHao = item.XuHao,
                        Code = item.Code,
                        Name = item.Name,
                        SpecificationModel = item.SpecificationModel,
                        Unit = item.Unit,
                        InspectionMethod = item.InspectionMethod,
                        BrandName = item.BrandName,
                        BindQuantity = item.BindQuantity,
                        SupplerCode = item.SupplerCode,
                        IsJiaJi = item.IsJiaJi,
                        ContainerVsMaterialStatus = CommonStatus.ENABLE
                    };
                    await _wareContainerVsMaterialRep.InsertNowAsync(enableList);
                }

                //新增任务
                taskModel = new WareTask()
                {
                    OrderNo = OrderNo,
                    TaskModel = TaskModel.SHOUDONG,
                    TaskType = TaskType.Out,
                    TaskNo = YitIdHelper.NextId().ToString(),
                    TaskName = order.OrderType == IssueTypeEnum.DIAOBO ? TaskNameConst.DiaoBoDan_ManualOut : TaskNameConst.ShouDongDan_ManualOut,
                    TaskStatus = TaskStatusEnum.Complete,
                    Priority = 1,
                    ContainerCode = orderDetails.ContainerCode,
                    FromLocationCode = orderDetails.LocationCode,
                    ToLocationCode = "N/A",
                    UpdatedUserId = CurrentUserInfo.UserId,
                    UpdatedUserName = CurrentUserInfo.Name,
                    UpdatedTime = DateTimeOffset.Now
                };
                await _wareTaskRep.InsertNowAsync(taskModel);

                //更新库位
                locationModel.LocationStatus = LocationStatusEnum.kongxian;
                locationModel.IsEmptyContainer = YesOrNot.N;
                locationModel.Attribute = "小";
                await _wareLocationRep.UpdateAsync(locationModel);

                //更新关系表
                wareLocationVsContainer.LocationVsContainerStatus = CommonStatus.DELETED;
                await _wareLocationVsContainerRep.UpdateAsync(wareLocationVsContainer);

                //更新托盘状态
                wareContainer.ContainerStatus = ContainerStatusEnum.fenjian;
                await _wareContainerRep.UpdateAsync(wareContainer);
            }

            if (stockModel.CurrentQuantity >= orderDetails.OrderQuantity && orderDetails.ActualQuantity < new decimal(0.00))
            {
                stockModel.CurrentQuantity -= orderDetails.OrderQuantity;
                orderDetails.ActualQuantity = orderDetails.OrderQuantity - orderDetails.ActualQuantity;
            }
            else if (stockModel.CurrentQuantity >= orderDetails.OrderQuantity && orderDetails.ActualQuantity > new decimal(0.00))
            {
                stockModel.CurrentQuantity -= orderDetails.OrderQuantity - orderDetails.ActualQuantity;
                orderDetails.ActualQuantity += orderDetails.OrderQuantity - orderDetails.ActualQuantity;
            }
            else
            {
                orderDetails.ActualQuantity += orderDetails.OrderQuantity - orderDetails.ActualQuantity;
                stockModel.CurrentQuantity -= orderDetails.ActualQuantity;
            }
            await _wareStockRep.UpdateAsync(stockModel);
            await _wareOrderDetailsRep.UpdateAsync(orderDetails);

            var OldOrderNo = "N/A";
            if (taskModel != null) OldOrderNo = taskModel.OrderNo;
            if (wareSortOrderModel != null) OldOrderNo = wareSortOrderModel.ContainerOrderNo;

            //空托不执行以下逻辑
            if (OldOrderNo == "N/A") return;

            var ContainerOrderNo = (await _wareContainerVsMaterialRep.FirstOrDefaultAsync(p => p.ContainerCode == orderDetails.ContainerCode
            && p.ContainerVsMaterialStatus == CommonStatus.DISABLE)).OrderNo;

            var wareSortOrder = await _wareSortOrderRep.FirstOrDefaultAsync(z => z.OrderNo == order.OrderNo && z.ContainerOrderNo == ContainerOrderNo && z.ContainerCode == orderDetails.ContainerCode
            && z.ProjectCode == orderDetails.ProjectCode && z.Code == orderDetails.Code && z.SpecificationModel == orderDetails.SpecificationModel && z.SortStatus != SortStatusEnum.Completed);
            if (wareSortOrder == null)
            {
                //新增分拣
                wareSortOrder = new WareSortOrder()
                {
                    OrderNo = order.OrderNo,
                    OrderDetailID = orderDetails.Id,
                    ContainerCode = orderDetails.ContainerCode,
                    ContainerOrderNo = OldOrderNo,
                    ProjectCode = orderDetails.ProjectCode,
                    Code = orderDetails.Code,
                    Name = orderDetails.Name,
                    SpecificationModel = orderDetails.SpecificationModel,
                    Unit = orderDetails.Unit,
                    InspectionMethod = orderDetails.InspectionMethod,
                    SortQuantity = orderDetails.ActualQuantity,
                    ActualQuantity = new decimal(0.00),
                    SortStatus = SortStatusEnum.NotProgram
                };
                await _wareSortOrderRep.InsertNowAsync(wareSortOrder);
            }
            else //存在分拣数量累加
            {
                if (wareSortOrder.SortQuantity < new decimal(0.00))
                    wareSortOrder.SortQuantity = orderDetails.OrderQuantity - orderDetails.ActualQuantity;
                else wareSortOrder.SortQuantity = orderDetails.ActualQuantity;

                await _wareSortOrderRep.UpdateAsync(wareSortOrder);
            }

            // 更新库存对于的库位编码
            if (stockModel.LocationCode != "N/A") stockModel.LocationCode = "N/A";
            await _wareStockRep.UpdateAsync(stockModel);
        }

        /// <summary>
        /// 打印出库单
        /// </summary>
        /// <returns></returns>
        [HttpGet("PrintWareOrder")]
        public async Task<PrintWareOrderDetailsOutput> PrintWareOrder([FromQuery] PrintWareOrderInput input)
        {
            var wareOrder = await _wareOrderRep.DetachedEntities.Where(z => z.Id == input.Id)
            .ProjectToType<WareOrder>().FirstOrDefaultAsync();
            if (wareOrder == null) throw Oops.Oh("数据不存在！");

            var auditCodeName = string.Empty; //定义审核码名称
            if (wareOrder.AuditCode == "Y") auditCodeName = "已审核";
            else if (wareOrder.AuditCode == "N") auditCodeName = "未审核";
            else auditCodeName = "未知";

            var orderCategoryName = string.Empty; //定义单据类型
            var wareDictData = await _wareDictDataRep.FirstOrDefaultAsync(z => z.Code == wareOrder.OrderCategory);
            orderCategoryName = wareDictData != null ? wareDictData.Value : "";

            var stockList = await _wareStockRep.Where(p => wareOrder.WareOrderDetails.Select(n => n.Code).ToList().Contains(p.Code) && p.LocationCode != "N/A" && !string.IsNullOrEmpty(p.LocationCode) 
            && (p.ContainerCode.StartsWith("TJ") || p.ContainerCode.StartsWith("P-TM") || p.ContainerCode.StartsWith("WG"))).ToListAsync();

            foreach (var item in wareOrder.WareOrderDetails)
            {
                var ckstcokModelList = stockList.Where(p => p.Code == item.Code).OrderBy(n => n.CreatedTime).OrderByDescending(n => n.CurrentQuantity).ToList();
                foreach (var stockitem in ckstcokModelList)
                {
                    var number = item.OrderQuantity - item.ActualQuantity;
                    if (stockitem.CurrentQuantity >= number)
                    {
                        item.ActualQuantity += number;
                    }
                    else
                    {
                        item.ActualQuantity += stockitem.CurrentQuantity;
                    }
                    item.LocationCode = stockitem.LocationCode;
                    item.ContainerCode = stockitem.ContainerCode;
                    break;
                }
            }

            return new PrintWareOrderDetailsOutput
            {
                OrderNo = wareOrder.OrderNo,
                OrderCategory = wareOrder.OrderCategory,
                OrderCategoryName = orderCategoryName,
                ProjectCode = wareOrder.WareOrderDetails != null ? wareOrder.WareOrderDetails.FirstOrDefault().ProjectCode : "",
                OrderQuantityTotal = wareOrder.OrderQuantityTotal,
                DepartmentNumber = wareOrder.DepartmentNumber,
                DepartmentNumberName = wareOrder.DepartmentNumber,
                OrderRemark = wareOrder.OrderRemark,
                AuditCode = wareOrder.AuditCode,
                AuditCodeName = auditCodeName,
                FactoryCode = wareOrder.FactoryCode,
                OrderDate = wareOrder.OrderDate,
                StationNumber = wareOrder.StationNumber,
                MainPartNumber = wareOrder.MainPartNumber,
                EquipmentNumber = wareOrder.EquipmentNumber,
                WareOrderDetails = wareOrder.WareOrderDetails.ToList()
            };
        }

        /// <summary>
        /// 打印分拣单
        /// </summary>
        /// <returns></returns>
        [HttpGet("PrintWareSortOrder")]
        public async Task<PrintWareSortOrderOutput> PrintWareSortOrder([FromQuery] PrintWareSortingOrderInput input)
        {
            //定义分拣单据
            var sortOrderList = new PrintWareSortOrderOutput();
            var wareSortOrdersList = new List<WareSortOrder>();
            

            //查询单据明细
            var wareOrder = await _wareOrderRep.Where(z => z.Id == input.Id).FirstOrDefaultAsync();
            sortOrderList.OrderNo = wareOrder.OrderNo;
            var wareOrderDetails = await _wareOrderDetailsRep.Where(z => z.OrderId == wareOrder.Id).ToListAsync();

            //根据单据明细查询分拣单
            foreach (var item in wareOrderDetails)
            {
                var wareSortOrders = await _wareSortOrderRep.DetachedEntities.Where(z => z.OrderDetailID == item.Id).FirstOrDefaultAsync();
                if (wareSortOrders != null) wareSortOrdersList.Add(wareSortOrders);
            }

            sortOrderList.sortOrderDetailss = wareSortOrdersList.Adapt<List<PrintWareSortOrderDetailsOutput>>();

            return sortOrderList;
        }

        /// <summary>
        /// 调拨单头-LES单据主表 数据同步使用
        /// </summary>
        [HttpGet("Order")]
        public async Task RedINVTA()
        {
            var invtaOutputList = await _erpRep
                .SqlQueryAsync<INVTAOutput>
                (@"select TA033,  --项目编号
	                      TA001,  --单别(1201、1202、1203、1204（12开头)
	                      TA002,  --单号
	                      TA003,  --交易日期（[FORMATE:YMD]）
						  TA004,  --部门编号
						  TA005,  --备注
                          TA006,  --审核码（Y/N/V）
						  TA008,  --工厂编号
	                      TA009,  --单据性质码（11.一般单据、12.调拨单）
	                      TA011,  --总数量
	                      TA014,  --单据日期
	                      TA015,  --审核者
	                      UDF01,  --（工位编号）用户自定义字段1
	                      UDF02,  --（主件品号）用户自定义字段1
	                      UDF08   --（设备编号）用户自定义字段1
                   from INVTA where TA001 in ('1201','1202','1203','1204','1299','2D01','1108','2205') and TA006='Y' and TA002!='20171219001' 
                   and TA009=12 and DATEDIFF(dd,TA014,GETDATE())<=1 order by TA014 desc");//TA001 like '12%' and 

            //循环判断LES系统中是否包含该调拨信息
            List<WareOrder> orderList = new List<WareOrder>();
            foreach (var invta in invtaOutputList)
            {
                var wareOrder = await _wareOrderRep.FirstOrDefaultAsync(u => u.OrderCategory == invta.TA001.Trim() && u.OrderNo == invta.TA002.Trim()
                && u.ProjectCode == invta.TA033.Trim() && u.OrderQuantityTotal == invta.TA011);

                //不存在执行新增操作
                if (wareOrder == null)
                {
                    var addOrder = new WareOrder()
                    {
                        Id = YitIdHelper.NextId(),
                        OrderNo = invta.TA002.Trim(),
                        OrderCategory = invta.TA001.Trim(),
                        OrderType = IssueTypeEnum.DIAOBO,
                        ProjectCode = invta.TA033.Trim(),
                        OrderQuantityTotal = invta.TA011,
                        DepartmentNumber = invta.TA004.Trim(),
                        OrderRemark = invta.TA005.Trim(),
                        AuditCode = invta.TA006.Trim(),
                        FactoryCode = invta.TA008.Trim(),
                        OrderDate = invta.TA014.Trim(),
                        StationNumber = invta.UDF01.Trim(),
                        MainPartNumber = invta.UDF02.Trim(),
                        EquipmentNumber = invta.UDF08.Trim(),
                        CreatedUserId = CurrentUserInfo.UserId,
                        CreatedUserName = CurrentUserInfo.Name,
                        CreatedTime = DateTimeOffset.Now
                    };
                    // 新增单据主表信息
                    await _wareOrderRep.InsertNowAsync(addOrder);

                    // 批量新增单据明细信息
                    var orderDetailsList = await RedINVTB(addOrder);
                    await _wareOrderDetailsRep.Context.BulkInsertAsync(orderDetailsList);
                }
                else
                {
                    // 批量新增单据明细信息
                    var orderDetailsList = await RedINVTB(wareOrder);
                    await _wareOrderDetailsRep.Context.BulkInsertAsync(orderDetailsList);
                }
            }
        }

        /// <summary>
        /// 调拨单身-Les单据明细表
        /// </summary>
        [HttpPost("orderdetails")]
        [NonAction]
        public async Task<List<WareOrderDetails>> RedINVTB(WareOrder order)
        {
            if (string.IsNullOrEmpty(order.OrderNo)) throw Oops.Oh(ErrorCode.D1011);
            var invtbOutputList = await _erpRep
                .SqlQueryAsync<INVTBOutput>
                (@"select  TB012,   --转出库
		                   TB013,   --转入库
		                   TB021,   --项目编号
		                   TB029,   --转出库位
		                   TB030,   --转入库位
		                   TB001,   --单别
		                   TB002,   --单号
		                   TB003,   --序号
		                   TB004,   --品号
		                   TB005,   --品名
		                   TB006,   --规格
		                   TB007,   --数量
		                   TB008,   --单位
		                   TB009,   --库存数量
						   TB018,   --审核码
						   CREATOR, --审核者
                           TB017,   --备注
                           UDF02    --参数
                   from INVTB where TB018='Y' and TB001='" + order.OrderCategory + "' and  TB002='" + order.OrderNo + "' and TB021='" + order.ProjectCode + "' order by CREATE_DATE desc");

            //循环判断LES系统中是否包含该调拨明细信息
            List<WareOrderDetails> orderDetailsList = new List<WareOrderDetails>();
            foreach (var invtb in invtbOutputList)
            {
                var isExists = await _wareOrderDetailsRep.AnyAsync(u => u.WareOrder.OrderCategory == invtb.TB001.Trim() && u.WareOrder.OrderNo == invtb.TB002.Trim()
                && u.ProjectCode == invtb.TB021.Trim() && u.Code == invtb.TB004.Trim() && u.SpecificationModel == invtb.TB006.Trim());

                //不存在执行新增操作
                if (!isExists)
                {
                    //获取物料的检验方式
                    var InspectionMethod = InspectionMethodEnum.mianjian;
                    var wareMateriaModel = await _wareMaterialRep.FirstOrDefaultAsync(n => n.Code == invtb.TB004.Trim()
                    && n.Name == invtb.TB005.Trim() && n.SpecificationModel == invtb.TB006.Trim());
                    if (wareMateriaModel != null) InspectionMethod = wareMateriaModel.InspectionMethod;

                    // 品牌名称查询
                    var wareMaterial = await _wareMaterialRep.FirstOrDefaultAsync(z => z.Code == invtb.TB004.Trim()
                    && z.Name == invtb.TB005.Trim() && z.SpecificationModel == invtb.TB006.Trim());

                    var addOrderDetails = new WareOrderDetails()
                    {
                        Id = YitIdHelper.NextId(),
                        OrderId = order.Id,
                        ProjectCode = invtb.TB021.Trim(),
                        XuHao = invtb.TB003.Trim(),
                        Code = invtb.TB004.Trim(),
                        Name = invtb.TB005.Trim(),
                        SpecificationModel = invtb.TB006.Trim(),
                        Unit = invtb.TB008.Trim(),
                        BrandName = wareMaterial == null || wareMaterial.BrandName == "无" ? "" : wareMaterial.BrandName,
                        InspectionMethod = InspectionMethod,
                        OrderQuantity = invtb.TB007,
                        ActualQuantity = new decimal(0.00),
                        SingleCategory = invtb.TB001.Trim(), //单别
                        TransferToIssue = invtb.TB012.Trim(), //转出库
                        TransferToReceipt = invtb.TB013.Trim(), //转入库
                        TransferOutLocation = invtb.TB029.Trim(), //转出库位
                        TransferredILocation = invtb.TB030.Trim(), //转入库位
                        OrderParameter = invtb.UDF02.Trim(), //参数
                        OrderRemark = invtb.TB017.Trim(), //备注
                        CreatedUserId = CurrentUserInfo.UserId,
                        CreatedUserName = CurrentUserInfo.Name,
                        CreatedTime = DateTimeOffset.Now
                    };
                    orderDetailsList.Add(addOrderDetails);
                }
            }

            return orderDetailsList;
        }

        #region 发货出库
        /// <summary>
        /// 新增发货单
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("AddShipment")]
        [UnitOfWork]
        public async Task AddShipment([FromBody] AddShipmentInput input)
        {
            if (input.WareOrderDetailss.Count == 0) throw Oops.Oh("出库物料不能为空");

            //系统生成出库单据号
            var orderNo = YitIdHelper.NextId().ToString();

            //构建出库单据主表信息
            var wareOrder = new WareOrder()
            {
                OrderNo = orderNo,
                OrderCategory = input.OrderCategory, //单别（1204_异库调拨单、1203_装配调拨单、1201_库位调拨单、2D01_零组件发货）
                OrderType = IssueTypeEnum.SHOUDONG,
                OrderStatus = IssueStausEnum.NOTZHIXING,
                ProjectCode = input.WareOrderDetailss.Select(t => t.ProjectCode).FirstOrDefault(),
                OrderQuantityTotal = input.WareOrderDetailss.Sum(t => t.OrderQuantity)
            };
            await _wareOrderRep.InsertAsync(wareOrder);

            //构建单据明细信息
            foreach (var item in input.WareOrderDetailss)
            {
                var orderDetails = item.Adapt<WareOrderDetails>();
                orderDetails.OrderId = wareOrder.Id;
                // 新增单据明细信息
                await _wareOrderDetailsRep.InsertAsync(orderDetails);
            }
        }

        /// <summary>
        /// 编辑单据出库发货
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("EditShipment")]
        [UnitOfWork]
        public async Task EditShipment([FromBody] EditOrderIssueInput input)
        {
            if (input.WareOrderDetailss.Count == 0) throw Oops.Oh("出库物料不能为空");

            var wareOrder = await _wareOrderRep.DetachedEntities.Where(z => z.Id == input.Id).ProjectToType<WareOrder>().FirstOrDefaultAsync();
            if (wareOrder == null) throw Oops.Oh("数据不存在");

            //删除原来单据明细记录
            foreach (var itemDetail in wareOrder.WareOrderDetails)
            {
                await _wareOrderDetailsRep.DeleteAsync(itemDetail);
            }

            // 更新单据主表项目编号和单据数
            wareOrder.ProjectCode = input.WareOrderDetailss.Select(t => t.ProjectCode).FirstOrDefault();
            wareOrder.OrderQuantityTotal = input.WareOrderDetailss.Sum(t => t.OrderQuantity);
            await _wareOrderRep.UpdateAsync(wareOrder);

            //构建单据明细信息
            foreach (var item in input.WareOrderDetailss)
            {
                var orderDetails = item.Adapt<WareOrderDetails>();
                orderDetails.OrderId = wareOrder.Id;

                // 新增单据明细信息
                await _wareOrderDetailsRep.InsertAsync(orderDetails);
            }
        }

        /// <summary>
        /// 新增发货预约
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("AddShipmentReservation")]
        [UnitOfWork]
        public async Task AddShipmentReservation([FromBody] ShipmentReservationInput input)
        {
            //查询单据信息
            var orderModel = await _wareOrderRep.Where(z => z.Id == input.Id).FirstOrDefaultAsync();
            if (orderModel == null) throw Oops.Oh("单据信息不存在!");

            var ShipmentReservation = input.ShipmentReservation;

            //新增发货单信息
            var shipmentReseration = ShipmentReservation.Adapt<ShipmentDeliveryAppointment>();
            shipmentReseration.ShipmentID = orderModel.Id;
            shipmentReseration.ShipmentNo = orderModel.OrderNo;
            shipmentReseration.Images = ShipmentReservation.Images != null && ShipmentReservation.Images.Count > 0 ? string.Join(",", ShipmentReservation.Images) : "N/A";

            await _shipmentDeliveryAppointment.InsertAsync(shipmentReseration);
        }
        #endregion 
    }
}
